

#include <gtk/gtk.h>
#include <stdio.h>
#include "support.h"
#include "memview.h"
#include "window.h"
#include "config.h"
#include "statusbar.h"
#include "toolbar_second.h"
#include "memfill.h"
#include "regflag.h"
#include "dialog.h"
#include "widget.h"

/*################ Static functions ##########################*/
static GtkWidget *gsim_get_memview(void);
static void reset_memview(void);
static void memview_goto_address(GtkWidget *which,gpointer data);
static void show_stack_call(void);

/*################ globals ####################*/
static GtkWidget *memview_tree;
GtkTreeModel *memview_model;
GtkTreeIter memview_iter;
GtkTreeSelection *memview_selector;
GObject *codeview_ref;     /*object on which refence of corsponding path is set*/

/*###################### Show / hide Memview ######################*/
void show_hide_memview(void)
{
	if(state_memview)
	{
		state_memview=0;
		gtk_widget_hide_all(gsim_memview_box);
		gsim_update_statusbar(DESC_SBAR,_("Memview off"));
	}
	else
	{
		state_memview=1;
		gtk_widget_show_all(gsim_memview_box);
		gsim_update_statusbar(DESC_SBAR,_("Memview on"));
	}
	return;
}

/*################# Data column edited #####################*/
void view_data_edited(GtkCellRendererText *cell,const gchar *path_string,const gchar *new_text,gpointer model)
{
	GtkTreeIter insertion_iter;
	GtkTreePath *insertion_path;
	gint i,m;
	gchar *final_value;
	gchar *ans=g_malloc(3);
	
	insertion_path = gtk_tree_path_new_from_string (path_string);
	gtk_tree_model_get_iter (GTK_TREE_MODEL(model), &insertion_iter,insertion_path);
	final_value=g_utf8_strup(new_text,2);
	
	if(*final_value=='\0')
		return;
	
	*ans='\0';
	m=2-g_utf8_strlen(final_value,-1);
	for(i=0;i<m;i++)
		g_strlcat(ans,"0",3);
	
	for(i=0;i<g_utf8_strlen(final_value,-1);i++)
	{
		if(g_unichar_isxdigit(*(final_value+i)))
			continue;
		else 
		{
			g_free(final_value);
			g_free(ans);
			return;
		}
	}
	g_strlcat(ans,final_value,3);
	gtk_list_store_set(GTK_LIST_STORE(model),&insertion_iter,1,ans,-1);
	g_free(final_value);
	g_free(ans);
}

/*################ reset the memview ######################*/
static void reset_memview(void)
{
	g_object_ref(G_OBJECT(memview_model));
	gtk_tree_view_set_model(GTK_TREE_VIEW(memview_tree),NULL);
	
	gint i;
	gchar addr[5];
	addr[4]='\0';
	GtkTreeIter memview_iter;
	gtk_tree_model_get_iter_first(memview_model,&memview_iter);
	for(i=gsim_values.memstart;i<=gsim_values.memend;i++)
	{
		sprintf(addr,"%04X",i);
		gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_ADDR_COL,addr,MEM_DATA_COL,"00",-1);
		gtk_tree_model_iter_next(memview_model,&memview_iter);
	}
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(memview_tree),memview_model);
	g_object_unref(G_OBJECT(memview_model));
	return;
}

/*#################### Scroll to the cell ########################*/
void memview_scroll_to_address(gint x)
{
	GtkTreePath *path;
	gint path_int;
	gchar path_str[10];
	path_int=x - gsim_values.memstart;
	snprintf(path_str,10,"%d",path_int);
	
	/*remove tracker from prevoius cell*/
	gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_TR_COL,NULL,-1);
	/*scroll to cell and place tracker there*/
	path=gtk_tree_path_new_from_string(path_str);
	gtk_tree_model_get_iter(memview_model,&memview_iter,path);
	gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(memview_tree),path,NULL,FALSE,0,0);
	gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_TR_COL,data_tracker_pixmap,-1);
	gtk_tree_selection_select_path(memview_selector,path);
	
	return;
}
	
/*#################### Go to the port in the find entry ###################*/
static void memview_goto_address(GtkWidget *which,gpointer data)
{
	const gchar *goto_path;
	goto_path=gtk_entry_get_text(GTK_ENTRY(data));
	if(g_ascii_strcasecmp(goto_path,""))
	{
		gint x;
		x=make_int__(goto_path);
		if(x<gsim_values.memstart||x>gsim_values.memend)
			return;
		
		memview_scroll_to_address(x);
	}
	return;
}

/*############## Change memory range #############*/
static void change_memory_range(gint start,gint end)
{
	if(start<0x0000||end>0xffff||start>end)
	{
		gsim_message(_("Invalid memory range specified."),GTK_MESSAGE_ERROR);
		return;
	}
	if(gsim_values.memstart==start&&gsim_values.memend==end)
		return;
	
	gsim_values.memstart=start;
	gsim_values.memend=end;
	
	/*first detach model and again attack later due to speed issues*/
	g_object_ref(G_OBJECT(memview_model));
	gtk_tree_view_set_model(GTK_TREE_VIEW(memview_tree),NULL);
	gtk_list_store_clear(GTK_LIST_STORE(memview_model));
	
	gint i;
	gchar addr[5];
	addr[4]='\0';
	for(i=gsim_values.memstart;i<=gsim_values.memend;i++)
	{
		sprintf(addr,"%04X",i);
		gtk_list_store_append(GTK_LIST_STORE(memview_model),&memview_iter);
		gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_ADDR_COL,addr,MEM_DATA_COL,"00",-1);
	}
	
	/*pack pixmap in third col*/
	gtk_tree_model_get_iter_first(memview_model,&memview_iter);
	gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_TR_COL,data_tracker_pixmap,-1);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(memview_tree),memview_model);
	g_object_unref(G_OBJECT(memview_model));
	
}

/*################ Change the memory range dialog ###################*/
void gsim_memview_change_range(void)
{
	GtkWidget *dialog;   
   /* Create the widgets */
   
   	dialog = gtk_dialog_new_with_buttons(_("Memory Range"),GTK_WINDOW(gsim_appwindow),GTK_DIALOG_MODAL,
											GTK_STOCK_CANCEL,GTK_RESPONSE_NONE,GTK_STOCK_OK,GTK_RESPONSE_OK,NULL);
                                       
	GtkWidget *table,*image,*label1,*label2,*entry1,*entry2;
	table=gtk_table_new(2,3,FALSE);
	image=gtk_image_new_from_stock(GTK_STOCK_INDEX,GTK_ICON_SIZE_DIALOG);
	label1=gtk_label_new(_("Memory Start: "));
	label2=gtk_label_new(_("Memory End:"));
	entry1=gtk_entry_new_with_max_length(4);
	gtk_entry_set_text(GTK_ENTRY(entry1),make_str__(gsim_values.memstart,4));
	gtk_widget_set_size_request(entry1 ,60,-1);
	g_signal_connect(entry1,"changed",G_CALLBACK(on_address_changed),NULL);
	entry2=gtk_entry_new_with_max_length(4);
	gtk_entry_set_text(GTK_ENTRY(entry2),make_str__(gsim_values.memend,4));
	gtk_widget_set_size_request(entry2 ,60,-1);
	g_signal_connect(entry2,"changed",G_CALLBACK(on_address_changed),NULL);
	gtk_table_attach(GTK_TABLE(table),image ,0 ,1 ,0 ,2 ,0 ,0 ,5 ,5 );
	gtk_table_attach(GTK_TABLE(table), label1, 1,2 ,0 ,1 , 0,0 ,0 ,0 );
	gtk_table_attach(GTK_TABLE(table), label2,1 ,2 , 1, 2, 0, 0,0 ,0 );
	gtk_table_attach(GTK_TABLE(table),entry1 , 2, 3, 0, 1, 0,0 ,0 ,0 );
	gtk_table_attach(GTK_TABLE(table),entry2 , 2,3 ,1 ,2 , 0, 0, 0, 0);
	
	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),table);
	gtk_widget_show_all(dialog);

   /*decide what to do*/
   gint response;
   response=gtk_dialog_run(GTK_DIALOG(dialog));
   
   if(response==GTK_RESPONSE_OK)
   {
	   gint start=make_int__(gtk_entry_get_text(GTK_ENTRY(entry1)));
	   gint end=make_int__(gtk_entry_get_text(GTK_ENTRY(entry2)));
	   change_memory_range(start,end);
   }
	
   gtk_widget_destroy(dialog);
}

/*############## Show the stack ################*/
static void show_stack_call(void)
{
	gsim_set_registers();
	memview_scroll_to_address(sp_value);
}

/*################ Make the memory view box ####################*/
GtkWidget *gsim_get_memview_box( void )
{
	GtkWidget *memview_table;
	memview_table=gtk_table_new( 6,4,FALSE);
	
	/*memview label*/
	GtkWidget *memview_label;
	memview_label=gtk_label_new("MEMORY");
	gtk_table_attach(GTK_TABLE(memview_table),memview_label,0,3,0,1,0,0,5,0);
	
	/*pack close button*/
	GtkWidget *memview_close;
	memview_close=gsim_small_close_button_new(-1,-1);
	gtk_table_attach( GTK_TABLE( memview_table ), memview_close, 3 , 4 , 0 , 1 , 0 , 0, 0 , 0 );
	gtk_tooltips_set_tip( gsim_tooltips, memview_close, _("Close Memory View"),NULL);
	g_signal_connect(memview_close,"clicked",G_CALLBACK(show_hide_memview),NULL);
	
	/*pack the seperater*/
	GtkWidget *sep1;
	sep1=gtk_hseparator_new( );
	gtk_table_attach( GTK_TABLE( memview_table ), sep1, 0 , 4 , 1 , 2 , GTK_FILL|GTK_EXPAND , 0, 0 , 2 );
	
	/*pack the reset button*/
	GtkWidget *memview_reset;//,*reset_label;
	memview_reset=gsim_small_reset_button_new(-1,-1);
/*	reset_label=gtk_label_new("<span size=\"small\">R</span>");
	gtk_label_set_use_markup(GTK_LABEL(reset_label),TRUE);
	gtk_container_add(GTK_CONTAINER(memview_reset),reset_label);
	gtk_button_set_relief(GTK_BUTTON(memview_reset), GTK_RELIEF_HALF);
	gtk_widget_set_size_request( memview_reset , 20, 20 );*/
	gtk_table_attach( GTK_TABLE( memview_table ), memview_reset, 0 , 1 , 2 , 3 , 0 , 0, 0 , 0 );
	gtk_tooltips_set_tip( gsim_tooltips, memview_reset, _("Reset the memory cells"),NULL);
	g_signal_connect(memview_reset,"clicked",G_CALLBACK(reset_memview),NULL);
	
	/*pack the show_stack button*/
	GtkWidget *show_stack;//,*show_stack_label;
	show_stack=gsim_small_stack_button_new(-1,-1);
/*	show_stack_label=gtk_label_new("<span size=\"small\">S</span>");
	gtk_label_set_use_markup(GTK_LABEL(show_stack_label),TRUE);
	gtk_container_add(GTK_CONTAINER(show_stack),show_stack_label);
	gtk_button_set_relief(GTK_BUTTON(show_stack), GTK_RELIEF_HALF);
	gtk_widget_set_size_request( show_stack , 20, 20 );*/
	gtk_table_attach( GTK_TABLE( memview_table ), show_stack, 3 , 4 , 2 , 3 , 0 , 0, 0 , 0 );
	gtk_tooltips_set_tip( gsim_tooltips, show_stack, _("Show the stack location"),NULL);
	g_signal_connect(show_stack,"clicked",G_CALLBACK(show_stack_call),NULL);
	
	/*pack two unsused buttons*/
	GtkWidget *mem_1;
	mem_1=gsim_empty_button_new(-1,-1);
	/*gtk_button_set_relief(GTK_BUTTON(mem_1), GTK_RELIEF_NONE);
	gtk_widget_set_size_request( mem_1 , 20, 20 );*/
	gtk_table_attach( GTK_TABLE( memview_table ), mem_1, 1 , 2 , 2 , 3 , 0 , 0, 0 , 0 );
	//gtk_widget_set_sensitive(mem_1,FALSE);
	
	GtkWidget *mem_2;
	mem_2=gsim_empty_button_new(-1,-1);
	/*gtk_button_set_relief(GTK_BUTTON(mem_2), GTK_RELIEF_HALF);
	gtk_widget_set_size_request( mem_2 , 20, 20 );*/
	gtk_table_attach( GTK_TABLE( memview_table ), mem_2, 2 , 3 , 2 , 3 , 0 , 0, 0 , 0 );
	
	/*pack the memory location find entry and button*/
	GtkWidget *memfind_box,*memfind_entry,*memfind_button;
	memfind_box=gtk_hbox_new(FALSE,0);
	memfind_entry=gtk_entry_new_with_max_length(4);
	gtk_entry_set_text(GTK_ENTRY(memfind_entry),gsim_values.memfind);
	gtk_widget_set_size_request( memfind_entry ,60,-1);
	memfind_button=gsim_find_button_new(-1,-1);
//	gtk_widget_set_size_request( memfind_button ,25,-1);
	gtk_button_set_relief(GTK_BUTTON(memfind_button), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(memfind_box),memfind_entry,0,0,0);
	gtk_box_pack_start(GTK_BOX(memfind_box),memfind_button,0,0,0);
	gtk_table_attach( GTK_TABLE( memview_table ), memfind_box, 0 , 4 , 3 , 4 , 0 , 0, 0 , 0 );
	gtk_tooltips_set_tip( gsim_tooltips, memfind_entry, _("Enter a address to find"),NULL);
	gtk_tooltips_set_tip( gsim_tooltips, memfind_button, _("Find the address"),NULL);
	g_signal_connect(memfind_entry,"changed",G_CALLBACK(on_address_changed),NULL);
	g_signal_connect(memfind_entry,"activate",G_CALLBACK(memview_goto_address),memfind_entry);
	g_signal_connect(memfind_button,"clicked",G_CALLBACK(memview_goto_address),memfind_entry);
	
	/*pack the scorrlled window containing gsim_mem_tree*/
	GtkWidget *memview_scroll;
	memview_scroll=gtk_scrolled_window_new(NULL,NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(memview_scroll),GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(memview_scroll),GTK_SHADOW_IN);
	gtk_table_attach( GTK_TABLE( memview_table ), memview_scroll, 0 , 4 , 4 , 6 , 
											GTK_FILL|GTK_SHRINK , GTK_FILL|GTK_EXPAND, 0 , 0 );
	gtk_container_add(GTK_CONTAINER(memview_scroll),gsim_get_memview());
	
	/*pack in frame and return*/
	GtkWidget *memview_frame;
	memview_frame=gtk_frame_new(NULL);
	gtk_container_add(GTK_CONTAINER(memview_frame),memview_table);
	
	/*This is the object which contains page and path info in the
		codeview from which it comes*/
	codeview_ref=g_object_new(G_TYPE_OBJECT,NULL);
	
	return memview_frame;
}

/*###########################Memview Tree ############################*/
static GtkWidget *gsim_get_memview(void)
{
	GtkListStore *memview_store;
	
	memview_store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,GDK_TYPE_PIXBUF);
	memview_tree=gtk_tree_view_new_with_model(GTK_TREE_MODEL(memview_store));
	memview_model=gtk_tree_view_get_model(GTK_TREE_VIEW(memview_tree));
	memview_selector=gtk_tree_view_get_selection(GTK_TREE_VIEW(memview_tree));

	g_object_unref(G_OBJECT(memview_store));
	
	/*------------make the columns and cells--------------------*/
	GtkTreeViewColumn *memview_column;
	GtkCellRenderer *memview_address,*memview_data,*memview_tracker;
	
	memview_address=gtk_cell_renderer_text_new();
	g_object_set(G_OBJECT(memview_address),"cell-background",gsim_colors.memview_addr_bg,NULL);
	memview_column=gtk_tree_view_column_new_with_attributes("AD#",memview_address,"text",MEM_ADDR_COL,NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(memview_tree),memview_column);

	memview_data=gtk_cell_renderer_text_new();
	g_object_set(G_OBJECT(memview_data),//"background",gsim_colors.memview_data_bg,
	                   						"foreground",gsim_colors.memview_data_fg,"editable",TRUE,NULL);
	memview_column=gtk_tree_view_column_new_with_attributes("D#",memview_data,"text",MEM_DATA_COL,NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(memview_tree),memview_column);
	g_signal_connect(memview_data,"edited",G_CALLBACK(view_data_edited),memview_model);
	
	memview_tracker=gtk_cell_renderer_pixbuf_new();
	g_object_set(G_OBJECT(memview_tracker),"cell-background","gray66",NULL);
	gtk_tree_view_column_pack_end(memview_column,memview_tracker,FALSE);
	gtk_tree_view_column_set_attributes(memview_column,memview_tracker,"pixbuf",MEM_TR_COL,NULL);
	
	gtk_tooltips_set_tip(gsim_tooltips,memview_tree,"ADDRESS : DATA",NULL);
	
	/*initilise the data in the memview*/
	/*first detach model and again attack later due to speed issues*/
	g_object_ref(G_OBJECT(memview_model));
	gtk_tree_view_set_model(GTK_TREE_VIEW(memview_tree),NULL);
	
	gint i;
	gchar addr[5];
	addr[4]='\0';
	for(i=gsim_values.memstart;i<=gsim_values.memend;i++)
	{
		sprintf(addr,"%04X",i);
		gtk_list_store_append(GTK_LIST_STORE(memview_model),&memview_iter);
		gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_ADDR_COL,addr,MEM_DATA_COL,"00",-1);
	}
	
	/*pack pixmap in third col*/
	gtk_tree_model_get_iter_first(memview_model,&memview_iter);
	gtk_list_store_set(GTK_LIST_STORE(memview_model),
									&memview_iter,MEM_TR_COL,data_tracker_pixmap,-1);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(memview_tree),memview_model);
	g_object_unref(G_OBJECT(memview_model));

	return memview_tree;
}
